var id;

var text_color = "#222222";


var ps = new function() {
  var frames; // holds all frames of the game. frames are HTMLDivElements

  var gbs; // game boards
  var cgi = 0; // current game board index
  var cei = 0; // current element in current game board
  var ces; // current (missing) element's symbol (gbs[cgi].removed_elements[cei])

  // create game board, zoom game board
  var create, zoom;

  // intro periodic table, intro periodic squares, review periodic squares,
  // review atomic model, game board frame, choose missing square,
  // confirm choice result
  var ipt, ips, rps, ram, gbf, cms, ccr, scf;
  this.init = function(game_id, game_boards) {
    id = game_id
    gbs = game_boards;
    if (gbs != null && gbs.length > 0) {
      ces = gbs[cgi].removed_elements[cei] // current missing square's symbol
    }

    create = $("#create")[0];
    zoom = $("#zoom")[0];

    ipt = $("#ipt")[0]; // intro to periodic table
    ips = $("#ips")[0]; // intro to periodic squares
    rps = $("#rps")[0]; // review of periodic square
    ram = $("#ram")[0]; // review of atomic model
    gbf = $("#gbf")[0]; // game board frame
    cms = $("#cms")[0]; // choose missing square
    ccr = $("#ccr")[0]; // confirm choice result
    scf = $("#scf")[0]; // score screen frame

    frames = [create, zoom, ipt, ips, rps, ram, gbf, cms, ccr, scf];

    if (cms != null) {
      cms.am = $(cms).find("canvas.am")[0]; // atomic model of missing element
      cms.di = $(cms).find("div.drop-instruction")[0];
      cms.sps = $(cms).find("canvas.sps")[0]; // selected periodic square
      cms.confirm = $(cms).find("button.confirm")[0];
      cms.am.ctx = cms.am.getContext("2d");
      cms.as = new Array();
      for (var i = 0; i < 4; i++) {
        cms.as[i] = $(cms).find("canvas.ps" + i)[0];
        cms.as[i].ctx = cms.as[i].getContext("2d");
      }
    }
  };

  this.selectElement = function(s) {
    var scale = 160;
    var ctx = $(create).find("canvas")[0].getContext("2d");
    for (var i in s2e) {
      if (s2e[i].group == s2e[s].group && s2e[i].removed) {
        ctx.drawPeriodicSquare(s2e[i], s2e[i].getColumn() * scale, s2e[i].getRow() * scale, scale, false);
        s2e[i].removed = false;
      }
    }
    ctx.drawAtomicModel(s2e[s], s2e[s].getColumn() * scale, s2e[s].getRow() * scale, scale);
    s2e[s].removed = true;
  };

  this.showCreateGameBoard = function() {
    hideDivs(frames);
    $(create).show();
    
    for (var s in s2e) {
      s2e[s].removed = false;
    }
    var c = $(create).find("canvas")[0];
    c.ctx = c.getContext("2d");
    c.ctx.drawTable(0, 0, 160, true);
    c.addEventListener("click", mouseClick, true);
  };

  this.saveGameBoard = function() {
    var game_board = { "removed_elements" : []};
    for (var s in s2e) {
      var e = s2e[s];
      if (e.removed) {
        game_board.removed_elements[e.getColumn()] = s;
      }
    }
    if (game_board.removed_elements.length != 4) {
      alert("Please select one element from each column.");
      return;
    }
    game.createPiece(id, "game_board", JSON.stringify(game_board));
  };

  this.zoomGameBoard = function(i, scale) {
    var gb = gbs[i];
    for (var s in s2e) {
      s2e[s].removed = ($.inArray(s, gb.removed_elements) >= 0);
    }
    var ctx = $(zoom).find("canvas")[0].getContext("2d");
    ctx.drawTable(0, 0, scale);
    $(zoom).show();
  };

  this.deleteGameBoard = function(id) {
    if (!confirm("Are you sure you want to delete this game board?")) {
      return;
    }
    game.deletePiece("game_board", id);
  };

  this.showIntro = function() {
    hideDivs(frames);
    $(ipt).show();
  };

  this.showReview = function() {
    hideDivs(frames);
    $(ips).show();
    $(ips).find("#sample-model")[0].getContext("2d").drawAtomicModel(s2e["Cl"], 0, 10, 200);
    $(ips).find("#sample-square")[0].getContext("2d").drawPeriodicSquare(s2e["Cl"], 0, 10, 200);
  };

  this.showPeriodicSquareAnatomy = function() {
    hideDivs(frames);
    $(rps).show();

    var psa = $(rps).find("canvas")[0];
    psa.ctx = psa.getContext("2d");

    var scale = 300;
    var x = psa.width / 2 - scale;
    var y = (psa.height - scale) / 2;
    psa.ctx.drawPeriodicSquareAnatomy(x, y, scale);
  };

  this.showAtomicModelAnatomy = function() {
    hideDivs(frames);
    $(ram).show();

    var ama = $(ram).find("canvas")[0];
    ama.ctx = ama.getContext("2d");

    var scale = 200;
    var x = (ama.width - scale * 3) / 2;
    var y = (ama.height - scale * 2) / 2;
    ama.ctx.drawAtomicModelAnatomy(x, y, scale);
  };

  this.showGameBoard = function() {
    hideDivs(frames);
    $(gbf).show();
    $(gbf).find("canvas")[0].getContext("2d").drawGameBoard(gbs[cgi], 160);
  };

  this.showChooseMPS = function() {
    hideDivs(frames);
    $([cms.sps, cms.confirm]).hide();
    $([cms, cms.di]).show();
    cms.am.ctx.drawAtomicModel(s2e[ces], 0, 0, 200);

    var symbols = $.map(s2e, function(n) {return n.symbol});
    cms.answers = new Array();
    for (var i = 0; i < 4;) {
      var a = symbols[Math.floor(Math.random() * symbols.length)]; // random symbol
      if ($.inArray(a, cms.answers) < 0 && a != ces) {
        cms.answers.push(a);
        i++;
      }
    }
    cms.answers[Math.floor(Math.random() * 4)] = ces;

    for (var j = 0; j < 4; j++) {
      cms.as[j].ctx.drawPeriodicSquare(s2e[cms.answers[j]], 0, 0, 180, true);
    }

    dnd.setStartCallBack(function(s, v) {
      $([cms.sps, cms.confirm]).hide();
      $(cms.di).show();
    });
    dnd.setDropCallBack(dropMPS);
  };

  function dropMPS(target, value) {
    cms.sai = value; // selected answer index;
    cms.sps.getContext("2d").drawPeriodicSquare(s2e[cms.answers[value]], 0, 0, 180, true);
    $(cms.di).hide();
    $([cms.sps, cms.confirm]).show();
  };

  this.confirmChoice = function() {
    hideDivs(frames);
    $(ccr).show();
    var amc = $(ccr).find("canvas.am")[0];
    var psc = $(ccr).find("canvas.ps")[0];
    var next = $(ccr).find("button.next")[0];
    var score = $(ccr).find("button.score")[0];

    var e = s2e[cms.answers[parseInt(cms.sai)]];
    var s = e.symbol;
    var n = e.number;
    var v = e.valence;

    $(ccr).find("h3")[0].innerHTML = "Was " + e.symbol + " the right element?";
    amc.getContext("2d").drawAtomicModel(s2e[ces], 10, 0, 200);
    psc.getContext("2d").drawPeriodicSquare(s2e[ces], 30, 0, 180);
    var p = "<p>How many total electrons are shown in the model on the left?</p>";
    if (ces == e.symbol) {
      $([psc, next]).show();
      p += "<p>Right! They equal <b>element " + s + "\'s</b> atomic number shown in the square on the right.</p>";
      p += "<p>An element's atomic number is equal to its number of protons.</p>";

      cei++;
      if (cei == 4 && cgi + 1 == gbs.length) {
        $(score).show();
        $(next).hide();
      } else {
        if (cei == 4) { // cgi + 1 != gbs.length
          cei = 0;
          cgi++;
        }
        ces = gbs[cgi].removed_elements[cei];
      }
    } else {
      $([psc, next]).hide();
      p += "<p class=\"caption\"></p>"
      p += "<p>How do you find <b>" + s + "</b>'s atomic number in the periodic square?</p>";
      p += "<p class=\"caption\"></p>"
      p += "<p><b>" + s + "</b> has a different atomic number than the missing element.</p>";
      p += "<table class=\"buttons\" style=\"width: 600px;\"><tr><td class=\"a-center\">" +
        "<button onclick=\"ps.showPeriodicSquareAnatomy()\">Review</button>" +
        "</td><td class=\"a-center\">" +
        "<button onclick=\"ps.showChooseMPS()\">Try again</button>" +
        "</td></tr></table>";
    }
    $(ccr).find(".text")[0].innerHTML = p;
  };

  this.showScore = function() {
    hideDivs(frames);
    $(scf).show();
  };
};

CanvasRenderingContext2D.prototype.drawPeriodicSquareAnatomy = function(x, y, scale) {
  this.drawPeriodicSquare(s2e["H"], x, y, scale, false);

  this.fillStyle = text_color;
  this.drawLine(x + 0.7 * scale, y + 0.333 * scale, x + 1.15 * scale, y + 0.333 * scale);
  this.drawLine(x + 0.867 * scale, y + 0.65 * scale, x + 1.15 * scale, y + 0.65 * scale);
  this.drawLine(x + 0.7 * scale, y + 0.8 * scale, x + 1.15 * scale, y + 0.8 * scale);
  this.drawLine(x + 0.967 * scale, y + 0.9 * scale, x + 1.15 * scale, y + 0.9 * scale);

  this.font = Math.round(0.075 * scale) + "px sans-serif";
  this.drawLeftText("Element Symbol", x + 1.20 * scale, y + 0.333 * scale, 300);
  this.drawLeftText("Element Name", x + 1.20 * scale, y + 0.65 * scale, 300);
  this.drawLeftText("Atomic Mass Units", x + 1.20 * scale, y + 0.8 * scale, 300);
  this.drawLeftText("Atomic Number", x + 1.20 * scale, y + 0.9 * scale, 300);

};

CanvasRenderingContext2D.prototype.drawAtomicModelAnatomy = function(x, y, scale) {
  this.drawPeriodicSquare(s2e["H"], x, y, scale, false);
  this.drawPeriodicSquare(s2e["Li"], x, y + scale, scale, false);
  this.drawAtomicModel(s2e["Be"], x + scale, y + scale, scale);
  this.drawPeriodicSquare(s2e["F"], x + scale * 2, y + scale, scale, false);

  this.textAlign = "center";
  this.textBaseline = "bottom";
  this.font = "20px sans-serif";

  this.fillStyle = "#F7FF00";
  this.drawToolTip("Number of NON-VALENCE electrons", x + 1.36 * scale, y + 1.28 * scale, x + 1.9 * scale, y + 0.20 * scale);
  this.fillStyle = "#46B6FF";
  this.drawToolTip("Number of protons", x + 1.44 * scale, y + 1.45 * scale, x + 2.2 * scale, y + 0.44 * scale);
  this.fillStyle = "#3FB353";
  this.drawToolTip("Number of neutrons", x + 1.61 * scale, y + 1.45 * scale, x + 2.5 * scale, y + 0.68 * scale);
  this.fillStyle = "#F85102";
  this.drawToolTip("Number of VALENCE electrons", x + 1.94 * scale, y + 1.45 * scale, x + 2.8 * scale, y + 0.92 * scale);
};

CanvasRenderingContext2D.prototype.drawGameBoard = function(gb, scale) {
  for (s in s2e) {
    s2e[s].removed = $.inArray(s, gb.removed_elements) >= 0;
  }
  this.font = "20px sans-serif";
  this.textBaseline = "bottom";
  this.drawCenterText("1", 0.5 * scale, 20, scale);
  this.drawCenterText("2", 1.5 * scale, scale + 20, scale);
  this.drawCenterText("17", 2.5 * scale, scale + 20, scale);
  this.drawCenterText("18", 3.5 * scale, 20, scale);
  this.drawTable(0, 20, scale);
};

CanvasRenderingContext2D.prototype.drawTable = function(offsetX, offsetY, scale, buttons) {
  for (var s in s2e) {
    var e = s2e[s];
    var x = offsetX + e.getColumn() * scale;
    var y = offsetY + e.getRow() * scale;
    if (s2e[s].removed) {
      this.drawAtomicModel(e, x, y, scale);
    } else {
      this.drawPeriodicSquare(e, x, y, scale, false);
    }
    if (buttons) {
      btns.push(new Button(x, y, scale, scale, ps.selectElement, [s]));
    }
  }
};

CanvasRenderingContext2D.prototype.drawPeriodicSquare = function(e, x, y, scale, answer) {
  this.lineWidth = 0.003 * scale;

  if (answer) {
    this.fillStyle = "#AAAAAA";
  } else {
    switch (e.group) {
      case 1 : this.fillStyle = "#E6A73A"; break;
      case 2 : this.fillStyle = "#95F144"; break;
      case 17 : this.fillStyle = "#F8FF52"; break;
      case 18 : this.fillStyle = "#BD97C6"; break;
    }
  }
  this.strokeStyle = "#000000";
  this.fillRect(x, y, scale, scale);
  this.strokeRect(x, y, scale, scale);

  this.textAlign = "center";
  this.textBaseline = "middle";
  this.fillStyle = "#000000";
  this.font = Math.floor(scale * 0.5) + "px serif";
  this.fillText(e.symbol, x + scale * 0.5, y + scale * 0.33, scale);

  this.font = "small-caps " + Math.floor(scale * 0.16) + "px serif";
  this.fillText(e.name, x + scale * 0.5, y + scale * 0.64, scale);

  this.font = "small-caps " + Math.floor(scale * 0.12) + "px serif";
  this.fillText(e.weight, x + scale * 0.5, y + scale * 0.8, scale);

  this.textAlign = "right";
  this.fillText(e.number, x + scale * 0.95, y + scale * 0.90, scale);
};

CanvasRenderingContext2D.prototype.drawAtomicModel = function(e, x, y, scale) {
  this.lineWidth = 0.003 * scale;

  switch (e.group) {
    case 1 : this.fillStyle = "#E7DA70"; break;
    case 2 : this.fillStyle = "#C4FF62"; break;
    case 17 : this.fillStyle = "#FBFFBD"; break;
    case 18 : this.fillStyle = "#D3C4DB"; break;
  }
  this.strokeStyle = "#000000";
  this.font = Math.round(scale * 0.07) + "px serif";
  this.textAlign = "center";
  this.textBaseline = "middle";
  this.fillRect(x, y, scale, scale);
  this.strokeRect(x, y, scale, scale);

  // valence shell, inner shell, nucleus
  this.fillStyle = "#4D8FC5";
  this.fillCircle(x + scale * 0.5, y + scale * 0.5, scale * 0.48);
  this.strokeCircle(x + scale * 0.5, y + scale * 0.5, scale * 0.48);
  this.fillStyle = "#50A9D9";
  this.fillCircle(x + scale * 0.5, y + scale * 0.5, scale * 0.32);
  this.strokeCircle(x + scale * 0.5, y + scale * 0.5, scale * 0.32);
  this.fillStyle = "#68CFEC";
  this.fillCircle(x + scale * 0.5, y + scale * 0.5, scale * 0.16);
  this.strokeCircle(x + scale * 0.5, y + scale * 0.5, scale * 0.16);

  // protons, neutrons
  this.fillStyle = "#36009C";
  this.fillCircle(x + scale * 0.42, y + scale * 0.5, scale * 0.075);
  this.strokeCircle(x + scale * 0.42, y + scale * 0.5, scale * 0.075);
  this.fillStyle = "#1B7300";
  this.fillCircle(x + scale * 0.58, y + scale * 0.5, scale * 0.075);
  this.strokeCircle(x + scale * 0.58, y + scale * 0.5, scale * 0.075);
  this.fillStyle = "#FFFFFF";
  this.fillText("+" + e.number, x + scale * 0.42, y + scale * 0.5);
  this.fillText(e.neutrons + "N", x + scale * 0.58, y + scale * 0.5);

  // electrons
  this.fillStyle = "#F7FF00";
  this.fillCircle(x + scale * 0.333, y + scale * 0.333, scale * 0.075);
  this.strokeCircle(x + scale * 0.333, y + scale * 0.333, scale * 0.075);
  this.fillStyle = "#F06942";
  this.fillCircle(x + scale * 0.9, y + scale * 0.5, scale * 0.075);
  this.strokeCircle(x + scale * 0.9, y + scale * 0.5, scale * 0.075);
  this.fillStyle = "#000000";
  this.fillText("-" + (e.number - e.valence), x + scale * 0.333, y + scale * 0.333);
  this.fillText("-" + e.valence, x + scale * 0.9, y + scale * 0.5);
};
